feat: add PyPI publishing workflow and readme metadata#2915
Conversation
- Add readme = "README.md" to pyproject.toml for PyPI project description - Add manual publish-pypi.yml workflow using trusted publishers (OIDC) - Update release.yml install instructions to prefer PyPI The publish workflow is manually triggered after a release, checks out the specified tag, verifies version consistency, builds with uv, and publishes using trusted publishing (no API tokens required). Prerequisites before first use: - Take ownership of the specify-cli PyPI project (#2908) - Create a 'pypi' environment in repo settings - Configure trusted publisher on PyPI for this repo/workflow Closes #2908 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds release infrastructure to publish specify-cli to PyPI and improve the package’s PyPI description rendering, aligning with the goal that uv tool install specify-cli@latest works reliably.
Changes:
- Add
readme = "README.md"topyproject.tomlso PyPI renders the README. - Introduce a manual GitHub Actions workflow to build and publish to PyPI via trusted publishing (OIDC).
- Update release notes generation to prefer
uv tool install specify-cli@latest, with a source-install fallback.
Show a summary per file
| File | Description |
|---|---|
pyproject.toml |
Adds README metadata for PyPI rendering. |
.github/workflows/publish-pypi.yml |
New manual build+publish workflow using artifacts + OIDC trusted publishing. |
.github/workflows/release.yml |
Updates generated release install instructions to prefer PyPI installs. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Add actions: read permission (required for artifact upload/download) - Move version check after uv install and use uv run python (ensures Python >=3.11 with tomllib is available regardless of runner image) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Note that PyPI does not host image files, so relative image paths from your local repository (e.g., You can see this here: https://pypi.org/project/specify-cli/ , where the Spec Kit logo isn't rendered. |
PyPI does not host images from the repository, so relative paths like ./media/logo.webp render as broken images. Switch to absolute raw.githubusercontent.com URLs so images display on both GitHub and PyPI. Ref: pypi/warehouse#5246 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Convert remaining /media/ image path to absolute URL for PyPI - Pin release install to specific version (specify-cli==X.Y.Z) - Align setup-uv to v8.2.0 matching rest of CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use job-level permissions: actions:write on build (for upload-artifact), actions:read on publish (for download-artifact) - Include both @latest and pinned version in release notes - Add note that PyPI may lag behind the GitHub release Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Build job needs contents:read for checkout (job-level perms replace workflow-level) - Clarify that PyPI publishing is manually triggered, not automatic Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The new publish workflow should force checkout of refs/tags/<tag> (not a potentially ambiguous ref) to avoid publishing from an unintended branch with the same name.
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 1
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
Move tag format validation before checkout and use refs/tags/ prefix to ensure we always check out a tag, not a branch with the same name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The release notes currently recommend an invalid uv tool install ...@latest command, and the publish workflow would benefit from pinning Python explicitly for deterministic builds/version parsing.
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 3
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
- Convert all relative .md links in README to absolute GitHub URLs for PyPI rendering compatibility - Fix release notes: use 'uv tool install specify-cli' (no @latest) - Pin Python 3.13 via uv python install for deterministic builds and use python3 directly instead of uv run Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The new publish workflow likely won’t run as written (uv publish --trusted-publishing always), and the updated release notes can direct users to install an unaffiliated PyPI package prior to ownership transfer (supply-chain risk).
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 6
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
- Use actions/setup-python (pinned v6, Python 3.13) instead of uv python install for deterministic builds - Use python instead of python3 for setup-python compatibility - Remove unsupported --trusted-publishing always flag from uv publish (OIDC is auto-detected with id-token: write) - Update README install to lead with PyPI, source as fallback - Update installation guide: replace PyPI disclaimer with official package note, add PyPI as primary install method - Release notes: pin to exact version, clarify PyPI timing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The updated docs/README wording implies PyPI availability/ownership immediately, but the PR itself describes prerequisites and a post-release publish step—documentation should be conditioned to avoid misleading installs right after merge.
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 2
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
- README: note source install is useful when PyPI version lags - Installation guide: explain PyPI follows GitHub releases and may lag briefly; source installs are always immediately available Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The generated release notes use an invalid uv tool install version pin syntax (==), which is likely to fail when users follow the instructions.
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 1
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
uv tool install accepts PEP 508 specifiers when quoted. Add quotes around 'specify-cli==VERSION' so users can copy-paste directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
The updated install instructions should consistently use uv tool install specify-cli@latest (per the PR/issue goal) to avoid stale installs due to uv caching.
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 3
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
Use @latest to force a fresh PyPI resolve (bypasses uv's cached tool version), matching the issue acceptance criteria. Source install remains as fallback when PyPI lags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
A few user-facing instructions and workflow safety/clarity issues should be addressed to keep release docs reproducible and the publish workflow fail-fast on missing artifacts.
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 3
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
Release notes (versioned changelog) must always reference the specific release version, not @latest. Use 'specify-cli==VERSION' for reproducibility. Also clarify that PyPI publishing is 'performed after' (not 'follows') each release, making the manual nature clearer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
README/docs currently present PyPI installs as “official” even though the PR/issue context indicates PyPI ownership/publishing may not be in place at merge time, which can mislead users into installing an unaffiliated package.
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 2
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
| > [!NOTE] | ||
| > The official `specify-cli` package is published to [PyPI](https://pypi.org/project/specify-cli/) by the [github/spec-kit](https://github.com/github/spec-kit) maintainers. PyPI publishing is performed after each GitHub release and may lag briefly. Source installs from the GitHub repository are always available immediately. | ||
|
|
| Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](https://github.com/github/spec-kit/blob/main/docs/install/uv.md)): | ||
|
|
||
| ```bash | ||
| uv tool install specify-cli@latest | ||
| ``` |

Summary
Adds infrastructure for publishing
specify-clito PyPI, addressing #2908.Changes
pyproject.toml— addsreadme = "README.md"so PyPI displays the project description.github/workflows/publish-pypi.yml— new manual workflow for publishing to PyPI.github/workflows/release.yml— updates install instructions to preferuv tool install specify-cli@latestPublish Workflow Design
workflow_dispatch) — run after the release workflow completesv0.10.1)pyproject.tomlversionid-token: writepermissionpypiGitHub environment for deployment gatingPrerequisites Before First Use
specify-cliPyPI project (pending attestation in [Feature]: Take ownership of the specify-cli pypi.org project #2908 ✅)pypienvironment in repo settingsgithubspec-kitpublish-pypi.ymlpypiTesting
This workflow won't run until manually triggered with a valid tag, so it's safe to merge ahead of the PyPI ownership transfer.